﻿using System;
using System.Collections.Generic;
using Cms.Application.Admin.Views;
using Cms.Application.IO;
using Cms.Data;
using Cms.Domain;
using Cms.Domain.RepositoryInterfaces;

namespace Cms.Application.Admin.Presenters
{
    public class EditMenuPresenter : BasePresenter
    {
        private readonly Administrator _administrator;
        private readonly IEditMenuView _view;

        public IDiskAccess DiskAccess { get; set; }

        public EditMenuPresenter(IEditMenuView view)
            : this(view, new RepositoryFactory())
        {
            DiskAccess = new DiskAccess();
        }
        
        public EditMenuPresenter(IEditMenuView view, IRepositoryFactory repositoryFactory)
            : base(view, repositoryFactory)
        {
            _view = view;
            _administrator = AdministratorRepository.GetAdministrator(_view.AdministratorID);
            if (!_administrator.HasPermission.EditMenu)
                _view.RedirectToPermissionDeniedPage();
        }
        
        public void SetLocales()
        {
            _view.SetLocales(_administrator.CurrentSite.Locales);
        }
        
        public void Initialize()
        {
            if (_administrator.CurrentSiteLocale != null)
            {
                _view.SelectedLocaleID = _administrator.CurrentSiteLocale.ID;
            }
            SetVersions();
            if (_view.MenuID == -1)
            {
                _view.SubMenuBehaviour = SubMenuBehaviour.Toggle;
                _view.ItemIsActiveWhenSubItemIsActive = true;
                _view.ExtraWrapperSpans = 0;
            }
            else
            {
                RefreshProperties();
                Menu menu = SiteRepository.GetMenu(_view.MenuID, _administrator.CurrentSite.ID);
                _view.Code = menu.GetStyleSheetCode();
                SetItems();
            }
        }
                
        public void SetItems()
        {
            Menu menu = SiteRepository.GetMenu(_view.MenuID, _administrator.CurrentSite.ID);
            _view.SetItems(menu.Name, menu.GetVersion(_view.SelectedVersionID).GetRootItems());
        }
        
        public void RefreshProperties()
        {
            if (_view.MenuID < 0)
            {
                return;
            }
            Menu menu = SiteRepository.GetMenu(_view.MenuID, _administrator.CurrentSite.ID);
            _view.Name = menu.Name;
            _view.Description = menu.Description;
            _view.ItemIsActiveWhenSubItemIsActive = menu.ItemIsActiveWhenSubItemIsActive;
            _view.SubMenuBehaviour = menu.SubMenuBehaviour;
            _view.ActiveItemPrefix = menu.ActiveItemPrefix;
            _view.ExtraWrapperSpans = menu.ExtraWrapperSpans;
        }
        
        public void SaveSelectedLocale()
        {
            _administrator.CurrentSiteLocale = LocaleRepository.GetLocale(_view.SelectedLocaleID);
            AdministratorRepository.SaveAdministrator(_administrator);
        }
        
        public void Move(string draggedID, string dropzoneID, string dropzonePart)
        {
            Menu menu = SiteRepository.GetMenu(_view.MenuID, _administrator.CurrentSite.ID);
            MenuVersion version = menu.GetVersion(_view.SelectedVersionID);
            MenuItem targetItem = version.GetItem(int.Parse(dropzoneID.Substring(1)));
            MenuItem targetContainer = dropzoneID.Substring(0, 1) == "T" ? targetItem.Parent : targetItem;
            MenuItem movedItem = version.GetItem(int.Parse(draggedID.Substring(1)));
            if (movedItem != null && targetItem != null && movedItem.ID != targetItem.ID)
            {
                if (movedItem.IsParentTo(targetItem))
                {
                    AddValidationError(GetText(_view, "IsParentToTargetError"));
                }
                if (!version.CanItemBeNamedAndMovedTo(
                        movedItem.ID, 
                        _view.SelectedLocaleID,
                        movedItem.GetTranslation(_view.SelectedLocaleID).Name,
                        targetContainer))
                {
                    AddValidationError(GetText(_view, "NameCollisionError"));
                }
                if (!IsValid)
                {
                    return;
                }
                if (movedItem.Parent != null)
                {
                    movedItem.Parent.SubItems.Remove(movedItem);
                }
                if (dropzoneID.Substring(0, 1) == "M")
                {
                    if (targetContainer != null)
                    {
                        targetContainer.SubItems.Add(movedItem);
                    }
                }
                else 
                {
                    // dropzoneID.Substring(0, 1) == "T"
                    if (dropzonePart == "upper")
                    {
                        if (targetContainer == null)
                        {
                            version.Items.Remove(movedItem);
                            version.Items.Insert(version.Items.IndexOf(targetItem), movedItem);
                        }
                        else
                        {
                            targetContainer.SubItems.Insert(targetContainer.SubItems.IndexOf(targetItem), movedItem);
                        }
                    }
                    else
                    {
                        // dropzonePart == "lower"
                        if (targetContainer == null)
                        {
                            version.Items.Remove(movedItem);
                            if (version.GetRootItems().IndexOf(targetItem) < version.GetRootItems().Count - 1)
                            {
                                version.Items.Insert(version.Items.IndexOf(targetItem) + 1, movedItem);
                            }
                            else
                            {
                                version.Items.Add(movedItem);
                            }
                        }
                        else
                        {
                            if (targetContainer.SubItems.IndexOf(targetItem) < targetContainer.SubItems.Count - 1)
                            {
                                targetContainer.SubItems.Insert(targetContainer.SubItems.IndexOf(targetItem) + 1, movedItem);
                            }
                            else
                            {
                                targetContainer.SubItems.Add(movedItem);
                            }
                        }
                    }
                }
                movedItem.Parent = targetContainer;
                version.UpdateSortIndexes();
                SiteRepository.SaveMenu(menu);
            }
            SetItems();
        }
        
        public void DeleteMenuItem(int itemID)
        {
            Menu menu = SiteRepository.GetMenu(_view.MenuID, _administrator.CurrentSite.ID);
            MenuVersion version = menu.GetVersion(_view.SelectedVersionID);
            MenuItem deletedItem = version.GetItem(itemID);
            bool hasSameName = false;

            // Check for name collisions between sub items and items at the parent level
            IList<MenuItem> parentLevelItems = deletedItem.Parent == null
                                                   ? deletedItem.Version.GetRootItems()
                                                   : deletedItem.Parent.SubItems;
            foreach (MenuItem pli in parentLevelItems)
            {
                if (pli.ID == deletedItem.ID)
                {
                    continue;
                }
                foreach (MenuItem mi in deletedItem.SubItems)
                {
                    foreach (var kvp in mi.Translations)
                    {
                        if (pli.GetTranslation(kvp.Key).Name.ToLower() == mi.GetTranslation(kvp.Key).Name.ToLower())
                        {
                            AddValidationError(GetText(_view, "DeleteMenuItem_NameCollision"));
                            hasSameName = true;
                            break;
                        }
                    }
                }
                if (hasSameName)
                {
                    break;
                }
            }
            if (!IsValid)
            {
                return;
            }

            // Move all sub items to the parent item
            foreach (MenuItem subItem in deletedItem.SubItems)
            {
                subItem.Parent = deletedItem.Parent;
                if (deletedItem.Parent != null)
                {
                    deletedItem.Parent.SubItems.Add(subItem);
                }
            }
            deletedItem.SubItems.Clear();

            // Remove references to the deleted item
            deletedItem.Version = null;
            if (deletedItem.Parent != null)
            {
                deletedItem.Parent.SubItems.Remove(deletedItem);
            }
            version.Items.Remove(deletedItem);
            version.UpdateSortIndexes();
            SiteRepository.SaveMenu(menu);
            SetItems();
        }
        
        public void Save()
        {
            if (_view.Name.Trim() == string.Empty)
            {
                AddValidationError(GetText(_view, "NoNameError"));
            }
            if (!IsValid)
            {
                return;
            }
            Menu menu;
            if (_view.MenuID == -1)
            {
                menu = new Menu
                           {
                               Site = _administrator.CurrentSite,
                               StyleSheet = new SourceCode()
                           };
                var version = new MenuVersion
                                  {
                                      Parent = menu,
                                      EditedBy = _administrator,
                                      Timestamp = DateTime.Now.Ticks.ToString()
                                  };
                menu.Versions.Add(version);
                menu.Site.Menus.Add(menu);
                menu.StyleSheet.Site = _administrator.CurrentSite;
                menu.Name = _view.Name; // This is needed to be able to save
                menu.ItemIsActiveWhenSubItemIsActive = true;
                menu.SubMenuBehaviour = SubMenuBehaviour.Toggle;
                SiteRepository.SaveMenu(menu); // Save to obtain ID
                string css = DiskAccess.ReadTextFile("Admin\\Resources\\NewMenuStylesheet.css").Replace(".cmsMenu", ".cmsMenu" + menu.ID);
                _view.Code = css;
                menu.SetStyleSheetCode(css, _administrator);
                menu.PublishedVersion = version;
            }
            else
            {
                menu = SiteRepository.GetMenu(_view.MenuID, _administrator.CurrentSite.ID);
            }
            menu.Name = _view.Name;
            menu.Description = _view.Description;
            menu.ItemIsActiveWhenSubItemIsActive = _view.ItemIsActiveWhenSubItemIsActive;
            menu.SubMenuBehaviour = _view.SubMenuBehaviour;
            menu.ActiveItemPrefix = _view.ActiveItemPrefix;
            menu.ExtraWrapperSpans = _view.ExtraWrapperSpans;
            if (_view.CurrentTab == "css")
            {
                menu.SetStyleSheetCode(_view.Code, _administrator);
            }
            SiteRepository.SaveMenu(menu);
            DiskAccess.DeleteFile("__System\\Menus\\" + menu.ID + ".css");
            DiskAccess.CreateDirectory("__System\\Menus");
            DiskAccess.CreateTextFile("__System\\Menus\\" + menu.ID + ".css", _view.Code);
            if (_view.MenuID != -1)
            {
                return;
            }
            _view.SetMenuID(menu.ID);
            SetVersions();
        }
        
        public void Publish()
        {
        }

        private void SetVersions()
        {
            if (_view.MenuID > 0)
            {
                Menu menu = SiteRepository.GetMenu(_view.MenuID, _administrator.CurrentSite.ID);
                int publishedVersionID = -1;
                if (menu.PublishedVersion != null)
                {
                    publishedVersionID = menu.PublishedVersion.ID;
                }
                _view.SetVersions(menu.Versions, publishedVersionID);
            }
            else
            {
                _view.SetVersions(new List<MenuVersion>(), -1);
            }
        }
    }
}